package com.elegant.code.aop.zk;

import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * 同步锁 AOP
 * 创建者	张志朋
 * 创建时间	2015年6月3日
 * @transaction 中  order 大小的说明
 * https://docs.spring.io/spring/docs/4.3.14.RELEASE/spring-framework-reference/htmlsingle/#transaction-declarative-annotations
 * https://docs.spring.io/spring/docs/4.3.14.RELEASE/javadoc-api/
 */
@Component
@Aspect
@Order(1)//order越小越先执行，先执行的后结束，保证锁的有效性
public class ZkLockAspect {
	@Autowired
	private InterProcessMutex mutex;
	@Pointcut("@annotation(com.elegant.code.aop.zk.ZkLock)")
	public void lockAspect() {}
    @Around("lockAspect()")
    public  Object around(ProceedingJoinPoint joinPoint) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		ZkLock zkLock = method.getAnnotation(ZkLock.class);
		long waitTime = zkLock.waitTime();
		Object obj = null;
		boolean res = false;
		try {
			//只有等待超时，没有释放超时，比redis少一个
			res = mutex.acquire(waitTime, TimeUnit.SECONDS);
			obj = joinPoint.proceed();
		} catch (Throwable e) {
			e.printStackTrace();
			throw new RuntimeException();       
		} finally{
			if (res){//获取锁成功前提下才需要释放锁
				try {
					mutex.release();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
    	return obj;
    } 
}
